package com.lyncs.ods.modules.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.lyncs.ods.common.api.ResultCode;
import com.lyncs.ods.common.exception.ApiException;
import com.lyncs.ods.common.web.RequestHolder;
import com.lyncs.ods.config.WxMpConfiguration;
import com.lyncs.ods.constant.LyncsOdsConstant;
import com.lyncs.ods.domain.AdminUserDetails;
import com.lyncs.ods.modules.company.model.CompanyInfo;
import com.lyncs.ods.modules.company.service.CompanyInfoService;
import com.lyncs.ods.modules.msg.model.MsgValidateLog;
import com.lyncs.ods.modules.msg.service.MsgValidateLogService;
import com.lyncs.ods.modules.setting.model.CountryInfo;
import com.lyncs.ods.modules.setting.service.CountryInfoService;
import com.lyncs.ods.modules.user.model.*;
import com.lyncs.ods.modules.user.service.*;
import com.lyncs.ods.req.*;
import com.lyncs.ods.resp.UserCompanyResp;
import com.lyncs.ods.resp.UserInfoResp;
import com.lyncs.ods.security.util.JwtTokenUtil;
import com.lyncs.ods.utils.PageUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author alex
 * @date 2022/1/29 21:53
 * @description
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UserAuthInfoService userAuthInfoService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private UserLoginLogService userLoginLogService;
    @Autowired
    private CompanyInfoService companyInfoService;
    @Autowired
    private CompanyUserRelationService companyUserRelationService;
    @Autowired
    private CompanyUserRelationLogService relationRecordService;
    @Autowired
    private MsgValidateLogService msgValidateService;
    @Autowired
    private CountryInfoService countryInfoService;

    /**
     * 用户微信登录
     *
     * @param appid    appid
     * @param code     微信授权code
     * @param state    微信加密数据
     * @param platform 登录平台
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long login(String appid, String code, String state, String platform) throws WxErrorException {
        return register(appid, code, state, platform, Boolean.TRUE).getId();
    }

    @Override
    public UserInfo register(String appId, String code, String state, String platform, Boolean needRecord) throws WxErrorException {
        WxMpService wxMpService = WxMpConfiguration.getMpService(appId, WxMpServiceImpl.class);
        /*String date = DateUtil.format(new Date(), LyncsOdsConstant.Common.DATE_PATTERN);
        String md5 = MD5.create().digestHex(StringUtils.join(LyncsOdsConstant.Common.MD5_PREFIX, date));
        if (LyncsOdsConstant.AuthPlatform.WECHAT_WEB_APP.getKey().equals(platform) && !md5.equals(state)) {
            throw new ApiException(ResultCode.VALIDATE_FAILED);
        }*/
        WxOAuth2AccessToken oAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
        WxOAuth2UserInfo wxMpUser = wxMpService.getOAuth2Service().getUserInfo(oAuth2AccessToken, null);
        log.info("oAuth2AccessToken:{}", JSONUtil.parse(oAuth2AccessToken));
        log.info("wxMpUser:{}", JSONUtil.parse(wxMpUser));
        return register(appId, oAuth2AccessToken.getOpenId(), null, wxMpUser.getNickname(), wxMpUser.getHeadImgUrl(), oAuth2AccessToken.getAccessToken(), oAuth2AccessToken.getRefreshToken(), oAuth2AccessToken.getUnionId(), LyncsOdsConstant.AuthPlatform.WECHAT_WEB_APP.getKey(), needRecord);
    }

    private UserInfo register(String appId, String openId, String phone, String nickname, String avatar, String accessToken, String refreshToken, String unionId, String authType, Boolean needRecord) {
        UserInfo userInfo;
        //当前微信应用授权信息
        UserAuthInfo thisAppUserAuthInfo = null;
        List<UserAuthInfo> authInfos = userAuthInfoService.lambdaQuery().eq(UserAuthInfo::getUnionId, unionId).list();
        if (CollectionUtil.isNotEmpty(authInfos)) {
            Long userId = authInfos.get(0).getUserId();
            userInfo = userInfoService.lambdaQuery().eq(UserInfo::getId, userId).one();
            thisAppUserAuthInfo = authInfos.stream().filter(info -> info.getAppId().equals(appId) && info.getOpenId().equals(openId)).findFirst().orElse(null);
        } else {
            if (StringUtils.isEmpty(unionId)) {
                throw new ApiException("unionId 获取失败");
            }
            //当前用户未通过任何微信平台登录过，视为新用户
            Long userId = IdUtil.getSnowflakeNextId();
            userInfo = new UserInfo().setId(userId).setUsername(nickname).setPhone(phone).setAvatarUrl(avatar).setStatus(LyncsOdsConstant.UserStatus.INIT.getKey());
            userInfoService.save(userInfo);
        }

        if (Objects.isNull(thisAppUserAuthInfo)) {
            log.info("user has not registered the wechat app of {}, userId:{}", appId, userInfo.getId());
            thisAppUserAuthInfo = new UserAuthInfo().setUserId(userInfo.getId()).setAppId(appId).setAuthType(authType).setOpenId(openId).setNickname(nickname).setUnionId(unionId);
        }
        thisAppUserAuthInfo.setAccessToken(accessToken).setRefreshToken(refreshToken);
        userAuthInfoService.saveOrUpdate(thisAppUserAuthInfo);
        if (LyncsOdsConstant.UserStatus.DISABLE.getKey().equals(userInfo.getStatus())) {
            throw new ApiException(ResultCode.ACCOUNT_DISABLE);
        }
        if (needRecord) {
            saveTokenAndLog(userInfo, thisAppUserAuthInfo, accessToken, Boolean.FALSE);
        }
        return userInfo;
    }

    /**
     * 根据openID 获取jwt user
     *
     * @param openId openId
     * @return UserDetails
     */
    @Override
    public UserDetails loadUserByOpenId(String openId) {
        UserAuthInfo userAuthInfo = userAuthInfoService.lambdaQuery().eq(UserAuthInfo::getOpenId, openId).one();
        UserInfo userInfo = userInfoService.lambdaQuery().eq(UserInfo::getId, userAuthInfo.getUserId()).one();
        return loadUserDetails(userInfo, userAuthInfo);
    }

    @Override
    public void logout() {
        RequestHolder.removeCookie();
    }

    /**
     * list user companies(all available)
     *
     * @return all available companies
     */
    @Override
    public List<UserCompanyResp> listCompanies() {
        Long userId = RequestHolder.getUserId();
        UserInfo userInfo = userInfoService.lambdaQuery().eq(UserInfo::getId, userId).one();
        List<CompanyUserRelation> companyUserRelations = companyUserRelationService.lambdaQuery().eq(CompanyUserRelation::getUserId, userId).eq(CompanyUserRelation::getStatus, LyncsOdsConstant.BindStatus.BIND.getKey()).list();
        if (CollectionUtil.isEmpty(companyUserRelations)) {
            return null;
        }
        Map<Long, CompanyUserRelation> companyUserMap = companyUserRelations.stream().collect(Collectors.toMap(CompanyUserRelation::getCompanyId, o -> o, (o1, o2) -> o2));
        List<CompanyInfo> companyInfos = companyInfoService.getCompanyInfos(new ArrayList<>(companyUserMap.keySet()), LyncsOdsConstant.CompanyStatus.ENABLE.getKey(), PageUtil.getSortSql("id", userInfo.getRecentLoginCompanyId()));
        List<Long> countryIds = companyInfos.stream().map(CompanyInfo::getCountry).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Long, CountryInfo> countryMap = countryInfoService.lambdaQuery().in(CountryInfo::getId, countryIds).list().stream().collect(Collectors.toMap(CountryInfo::getId, o -> o));
        return companyInfos.stream().map(info -> {
            CountryInfo countryInfo = countryMap.get(info.getCountry());
            UserCompanyResp resp = new UserCompanyResp();
            resp.setCompanyId(info.getId());
            resp.setShortName(info.getShortName());
            resp.setAvatarUrl(info.getAvatarUrl());
            resp.setAddress(null);
            resp.setUserId(userId);
            resp.setRecentLoginCompanyId(userInfo.getRecentLoginCompanyId());
            resp.setCountryName(countryInfo == null ? null : countryInfo.getName());
            resp.setCurrency(countryInfo == null ? null : countryInfo.getCurrency());
            resp.setAdmin(LyncsOdsConstant.CompanyRole.ADMIN.getKey().equals(companyUserMap.get(info.getId()).getRole()));
            resp.setVip(LyncsOdsConstant.VIPStatus.VIP.getKey().equals(info.getLevelStatus()));
            return resp;
        }).collect(Collectors.toList());
    }

    /**
     * bind one company with login
     *
     * @param req request info
     */
    @Override
    public void bindCompany(BindCompanyReq req) {
        Long companyId = req.getCompanyId();
        Long userId = RequestHolder.getUserId();
        CompanyInfo companyInfo = companyInfoService.getCompanyInfo(companyId, null);
        if (Objects.isNull(companyInfo) || !LyncsOdsConstant.CompanyStatus.ENABLE.getKey().equals(companyInfo.getStatus())) {
            throw new ApiException("company not found or unavailable.");
        }
        CompanyUserRelation relation = companyUserRelationService.lambdaQuery().eq(CompanyUserRelation::getCompanyId, req.getCompanyId())
                .eq(CompanyUserRelation::getUserId, userId)
                .eq(CompanyUserRelation::getStatus, LyncsOdsConstant.EnableStatus.ENABLE.getKey())
                .one();
        if (Objects.isNull(relation)) {
            throw new ApiException("You are not an employee of this company.");
        }
        //更新最近登录企业
        userInfoService.lambdaUpdate().eq(UserInfo::getId, userId).set(UserInfo::getRecentLoginCompanyId, companyId).update();
        RequestHolder.saveCookie(LyncsOdsConstant.Header.COOKIE_PC, companyInfo.getId().toString());
        RequestHolder.saveCookie(LyncsOdsConstant.Header.COOKIE_ROLE, relation.getRole().toString());
    }

    /**
     * join one company by QR code
     *
     * @param req request info
     */
    @Override
    public void relateCompany(CompanyRelateReq req) {
        CompanyInfo companyInfo = companyInfoService.getCompanyInfo(req.getCompanyId(), null);
        if (Objects.isNull(companyInfo) || !LyncsOdsConstant.CompanyStatus.ENABLE.getKey().equals(companyInfo.getStatus())) {
            throw new ApiException("company not found or unavailable.");
        }
        companyUserRelation(RequestHolder.getUserId(), req.getCompanyId(), req.getRole());
        userInfoService.lambdaUpdate().eq(UserInfo::getId, RequestHolder.getUserId())
                .set(UserInfo::getRecentLoginCompanyId, req.getCompanyId())
                .update();
    }

    @Override
    public void saveUserInfo(SaveUserInfoReq req) {
        UserInfo userInfo = userInfoService.lambdaQuery().eq(UserInfo::getId, RequestHolder.getUserId()).one();
        if (Objects.isNull(userInfo)) {
            throw new ApiException("user not exist.");
        }
        //微信小程序不需要校验验证码
        if (StringUtils.isNotEmpty(req.getPhone()) && !LyncsOdsConstant.AuthPlatform.WECHAT_MINI_APP.getKey().equals(RequestHolder.getPlatform())) {
            checkSmsCode(RequestHolder.getUserId(), LyncsOdsConstant.MessageType.SMS, req.getCode());
        }
        if (StringUtils.isNotEmpty(req.getEmail()) && StringUtils.isEmpty(req.getPhone())) {
            checkSmsCode(RequestHolder.getUserId(), LyncsOdsConstant.MessageType.EMAIL, req.getCode());
        }
        userInfoService.lambdaUpdate().eq(UserInfo::getId, RequestHolder.getUserId())
                .set(StringUtils.isNotEmpty(req.getPhone()), UserInfo::getPhone, req.getPhone())
                .set(StringUtils.isNotEmpty(req.getEmail()), UserInfo::getEmail, req.getEmail())
                .set(StringUtils.isNotEmpty(req.getAvatarUrl()), UserInfo::getAvatarUrl, req.getAvatarUrl())
                .set(StringUtils.isNotEmpty(req.getNickname()), UserInfo::getUsername, req.getNickname())
                .set(LyncsOdsConstant.UserStatus.INIT.getKey().equals(userInfo.getStatus()), UserInfo::getStatus, LyncsOdsConstant.UserStatus.ENABLE.getKey())
                .update();
    }

    /**
     * 手机号登录
     *
     * @param phone    手机号
     * @param code     验证码
     * @param platform 授权平台
     */
    @Override
    public Long login(String phone, String code, String platform) {
        UserInfo userInfo = checkPhone(phone);
        if (LyncsOdsConstant.UserStatus.DISABLE.getKey().equals(userInfo.getStatus())) {
            throw new ApiException(ResultCode.ACCOUNT_DISABLE);
        }
        checkSmsCode(userInfo.getId(), LyncsOdsConstant.MessageType.SMS, code);
        UserAuthInfo userAuthInfo = userAuthInfoService.lambdaQuery().eq(UserAuthInfo::getUserId, userInfo.getId()).eq(UserAuthInfo::getAuthType, platform).one();
        saveTokenAndLog(userInfo, userAuthInfo, null, Boolean.TRUE);
        return userInfo.getId();
    }

    /**
     * get user info by token
     *
     * @param appId
     * @return user info
     */
    @Override
    public UserInfoResp getUserInfo(String appId) {
        String token = RequestHolder.getToken();
        Long userId = RequestHolder.getUserId();
        UserInfo userInfo = userInfoService.lambdaQuery().eq(UserInfo::getId, userId).ne(UserInfo::getStatus, LyncsOdsConstant.UserStatus.DISABLE.getKey()).one();
        //UserAuthInfo userAuthInfo = userAuthInfoService.lambdaQuery().eq(UserAuthInfo::getUserId, userId).eq(UserAuthInfo::getAuthType, authType).one();
        if (Objects.isNull(userInfo)) {
            throw new ApiException("用户不存在或已被禁用");
        }
        UserAuthInfo userAuthInfo = userAuthInfoService.lambdaQuery()
                .eq(UserAuthInfo::getUserId, userId)
                .eq(UserAuthInfo::getAppId, appId)
                .one();
        if (Objects.isNull(userAuthInfo)) {
            throw new ApiException("用户授权信息未找到");
        }
        return new UserInfoResp()
                .setAvatarUrl(userInfo.getAvatarUrl())
                .setEmail(userInfo.getEmail())
                .setNickname(userInfo.getUsername())
                .setPhoneNo(userInfo.getPhone())
                .setWeChatNickname(userAuthInfo.getNickname())
                .setStatus(userInfo.getStatus());
    }

    @Override
    public void bindThirdInfo(Integer type, String value, String code) {
        LyncsOdsConstant.MessageType messageType = Arrays.stream(LyncsOdsConstant.MessageType.values()).filter(msg -> msg.getKey().equals(type)).findAny().orElse(null);
        if (Objects.isNull(messageType)) {
            throw new ApiException("invalid type");
        }
        checkSmsCode(RequestHolder.getUserId(), messageType, code);
        userInfoService.lambdaUpdate().eq(UserInfo::getId, RequestHolder.getUserId())
                .set(LyncsOdsConstant.MessageType.SMS.getKey().equals(type), UserInfo::getPhone, value)
                .set(LyncsOdsConstant.MessageType.EMAIL.getKey().equals(type), UserInfo::getEmail, value)
                .update();
    }

    @Override
    public String generateDebuggerToken(String appId, String openId) {
        UserAuthInfo userAuthInfo = userAuthInfoService.lambdaQuery().eq(UserAuthInfo::getAppId, appId)
                .eq(UserAuthInfo::getOpenId, openId).last(" limit 1").one();
        UserInfo userInfo = userInfoService.lambdaQuery().eq(UserInfo::getId, userAuthInfo.getUserId()).one();
        saveTokenAndLog(userInfo, userAuthInfo, userAuthInfo.getAccessToken(), Boolean.FALSE);
        return RequestHolder.getCookie();
    }

    @Override
    public void bindWechat(String appId, String code) throws WxErrorException {
        WxMpService wxMpService = WxMpConfiguration.getMpService(appId, WxMpServiceImpl.class);
        WxOAuth2AccessToken oAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
        WxOAuth2UserInfo wxMpUser = wxMpService.getOAuth2Service().getUserInfo(oAuth2AccessToken, null);
        log.info("oAuth2AccessToken:{}", JSONUtil.parse(oAuth2AccessToken));
        log.info("wxMpUser:{}", JSONUtil.parse(wxMpUser));
        UserAuthInfo userAuthInfo = userAuthInfoService.lambdaQuery()
                .eq(UserAuthInfo::getUserId, RequestHolder.getUserId())
                .eq(UserAuthInfo::getAppId, appId)
                .one();
        if (userAuthInfo == null) {
            throw new ApiException("当前用户信息获取失败，请稍后再试");
        }
        String openId = oAuth2AccessToken.getOpenId();
        String unionId = oAuth2AccessToken.getUnionId();
        Integer count = userAuthInfoService.lambdaQuery()
                .eq(UserAuthInfo::getAppId, appId)
                .eq(UserAuthInfo::getAppId, appId)
                .count();
        if (count > 0) {
            throw new ApiException("该微信已绑定其它账号，请解绑后再试");
        }
        log.info("change wechat info, userId:{} openId: {}, original openId:{}", userAuthInfo.getUserId(), openId, userAuthInfo.getOpenId());
        userAuthInfo.setOpenId(openId)
                .setUnionId(unionId)
                .setRefreshToken(oAuth2AccessToken.getRefreshToken())
                .setAccessToken(oAuth2AccessToken.getAccessToken())
                .setNickname(wxMpUser.getNickname());
        userAuthInfoService.updateById(userAuthInfo);
    }

    @Override
    public String login(String appId, WxMpLogin entity) throws WxErrorException {
        WxMaService wxService = WxMpConfiguration.getMpService(appId, WxMaServiceImpl.class);
        // code换取session
        WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(entity.getCode());
        log.info("code换取session：{}", session);
        // 用户信息校验
        if (!wxService.getUserService().checkUserInfo(session.getSessionKey(), entity.getRawData(), entity.getSignature())) {
            throw new ApiException("用户信息校验失败");
        }
        // 解密用户信息
        WxMaUserInfo wxMaUserInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), entity.getEncryptedData(), entity.getIv());
        log.info("解密用户信息：{}", wxMaUserInfo);
        // 获取用户绑定手机号信息
        WxMaPhoneNumberInfo wxMaPhoneNumberInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), entity.getEncryptedData(), entity.getIv());
        log.info("获取用户绑定手机号信息：{}", wxMaPhoneNumberInfo);
        UserInfo userInfo = register(appId, session.getOpenid(), wxMaPhoneNumberInfo.getPhoneNumber(), wxMaUserInfo.getNickName(), wxMaUserInfo.getAvatarUrl(), null, null, wxMaUserInfo.getUnionId(), LyncsOdsConstant.AuthPlatform.WECHAT_MINI_APP.getKey(), Boolean.TRUE);
        return userInfo.getId().toString();
    }

    @Override
    public void savePhone(String appId, WxInfoReq wxInfoReq) throws WxErrorException {
        WxMaService wxService = WxMpConfiguration.getMpService(appId, WxMaServiceImpl.class);
        // code换取session
        WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(wxInfoReq.getCode());
        log.info("code换取session：{}", session);
        // 解密用户信息
        WxMaUserInfo wxMaUserInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), wxInfoReq.getEncryptedData(), wxInfoReq.getIv());
        log.info("解密用户信息：{}", wxMaUserInfo);
        // 获取用户绑定手机号信息
        WxMaPhoneNumberInfo wxMaPhoneNumberInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), wxInfoReq.getEncryptedData(), wxInfoReq.getIv());
        log.info("获取用户绑定手机号信息：{}", wxMaPhoneNumberInfo);
        if (wxMaPhoneNumberInfo == null || StringUtils.isEmpty(wxMaPhoneNumberInfo.getPhoneNumber())) {
            throw new ApiException("获取用户手机号失败");
        }
        UserInfo userInfo = userInfoService.getById(RequestHolder.getUserId());
        if (userInfo == null) {
            throw new ApiException("用户信息未找到");
        }
        log.info("update phone:{}=>{}", userInfo.getPhone(), wxMaPhoneNumberInfo.getPhoneNumber());
        userInfo.setPhone(wxMaPhoneNumberInfo.getPhoneNumber()).setStatus(LyncsOdsConstant.UserStatus.ENABLE.getKey());
        userInfoService.updateById(userInfo);
    }

    private UserDetails loadUserDetails(UserInfo userInfo, UserAuthInfo userAuthInfo) {
        return new AdminUserDetails(userInfo, userAuthInfo);
    }

    private void companyUserRelation(Long userId, Long cid, Integer role) {
        UserInfo userInfo = userInfoService.lambdaQuery().eq(UserInfo::getId, userId).one();
        companyUserRelationService.save(new CompanyUserRelation().setCompanyId(cid).setUserId(userId).setRole(role).setNickname(userInfo.getUsername()));
        relationRecordService.save(new CompanyUserRelationLog().setId(IdUtil.getSnowflakeNextId()).setUserId(userId).setCompanyId(cid).setStatus(LyncsOdsConstant.BindStatus.BIND.getKey()));
    }

    private void checkSmsCode(Long userId, LyncsOdsConstant.MessageType type, String code) {
        MsgValidateLog record = msgValidateService.lambdaQuery()
                .eq(MsgValidateLog::getType, type.getKey())
                .eq(MsgValidateLog::getUserId, userId)
                .eq(MsgValidateLog::getCount, 0)
                .eq(MsgValidateLog::getStatus, LyncsOdsConstant.MessageStatus.SUCCESS.getKey())
                .orderByDesc(MsgValidateLog::getCreateTime).last("limit 1").one();
        if (Objects.isNull(record) || !record.getCode().equals(code)) {
            throw new ApiException(type.getCode() + " verification code is wrong or expired.");
        }
        msgValidateService.lambdaUpdate().eq(MsgValidateLog::getId, record.getId())
                .set(MsgValidateLog::getStatus, LyncsOdsConstant.MessageStatus.VERIFIED.getKey())
                .update();
    }

    private UserInfo checkPhone(String phone) {
        UserInfo userInfo = userInfoService.lambdaQuery().eq(UserInfo::getPhone, phone).one();
        if (Objects.isNull(userInfo)) {
            throw new ApiException(ResultCode.PHONE_NOT_REGISTERED);
        }
        return userInfo;
    }

    private void saveTokenAndLog(UserInfo userInfo, UserAuthInfo userAuthInfo, String accessToken, Boolean checkPhone) {
        //save to jwt
        UserDetails userDetails = loadUserDetails(userInfo, userAuthInfo);
        //generate token
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = jwtTokenUtil.generateToken(userDetails);
        log.info("user login, id:{}, token:{}", userInfo.getId(), token);
        //此时还未选择登录公司
        UserLoginLog userLoginRecord = new UserLoginLog().setId(IdUtil.getSnowflakeNextId()).setToken(accessToken).setUserId(userInfo.getId());
        //insertLoginLog(username);
        userLoginLogService.save(userLoginRecord);
        if (checkPhone) {
            checkPhone(userInfo.getPhone());
        }
        RequestHolder.saveCookie(LyncsOdsConstant.Header.COOKIE_PT, token);
        RequestHolder.setData(LyncsOdsConstant.Header.AUTH_PLATFORM, userAuthInfo.getAuthType());
    }
}
